package middleware

import (
	"strconv"
	"time"

	"github.com/gin-gonic/gin"
)

// CORSConfig 跨域配置选项
type CORSConfig struct {
	AllowAllOrigins  bool
	AllowOrigins     []string
	AllowMethods     []string
	AllowHeaders     []string
	ExposeHeaders    []string
	AllowCredentials bool
	MaxAge           time.Duration
}

// DefaultCORSConfig 返回默认的CORS配置
func DefaultCORSConfig() CORSConfig {
	return CORSConfig{
		AllowAllOrigins: true,
		AllowMethods:    []string{"GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"},
		AllowHeaders: []string{"Origin", "Content-Length", "Content-Type", "Authorization",
			"Think-Lang", "Server"}, // 添加自定义头
		ExposeHeaders: []string{"Content-Length"},
		MaxAge:        12 * time.Hour,
	}
}

// CORS 创建一个处理跨域请求的中间件
func CORS() gin.HandlerFunc {
	return CORSWithConfig(DefaultCORSConfig())
}

// CORSWithConfig 使用自定义配置创建CORS中间件
func CORSWithConfig(config CORSConfig) gin.HandlerFunc {
	return func(c *gin.Context) {
		// 设置所有源允许访问
		if config.AllowAllOrigins {
			c.Header("Access-Control-Allow-Origin", "*")
		} else if len(config.AllowOrigins) > 0 {
			origin := c.GetHeader("Origin")
			for _, allowOrigin := range config.AllowOrigins {
				if origin == allowOrigin {
					c.Header("Access-Control-Allow-Origin", origin)
					break
				}
			}
		}

		// 如果是预检请求
		if c.Request.Method == "OPTIONS" {
			// 设置允许的请求方法
			if len(config.AllowMethods) > 0 {
				c.Header("Access-Control-Allow-Methods", join(config.AllowMethods))
			}

			// 设置允许的请求头
			if len(config.AllowHeaders) > 0 {
				c.Header("Access-Control-Allow-Headers", join(config.AllowHeaders))
			}

			// 设置暴露的响应头
			if len(config.ExposeHeaders) > 0 {
				c.Header("Access-Control-Expose-Headers", join(config.ExposeHeaders))
			}

			// 设置是否允许携带凭证
			if config.AllowCredentials {
				c.Header("Access-Control-Allow-Credentials", "true")
			}

			// 设置预检请求缓存时间
			if config.MaxAge > 0 {
				// 显式转换 float64 为 int
				c.Header("Access-Control-Max-Age", strconv.Itoa(int(config.MaxAge.Seconds())))
			}

			// 预检请求直接返回200
			c.AbortWithStatus(200)
			return
		}

		// 设置允许凭证
		if config.AllowCredentials {
			c.Header("Access-Control-Allow-Credentials", "true")
		}

		// 设置暴露的响应头
		if len(config.ExposeHeaders) > 0 {
			c.Header("Access-Control-Expose-Headers", join(config.ExposeHeaders))
		}

		c.Next()
	}
}

// join 辅助函数，将字符串切片合并为逗号分隔的字符串
func join(values []string) string {
	if len(values) == 0 {
		return ""
	}

	result := values[0]
	for i := 1; i < len(values); i++ {
		result += ", " + values[i]
	}

	return result
}
